#include <iostream>

class Base
{
public:
    virtual void show()
    {
        std::cout << "Base" << std::endl;
    }
};

class Derived : public Base
{
public:
    virtual void show()
    {
        std::cout << "Derived" << std::endl;
    }
};

int main()
{
// 1、静态转换：static_cast
#if 0
    // 使用场景1：基础数据类型转换
    int a = 97;
    // 窄转换：将一个int转换成char会有数据丢失、精度下降或结果不准确的风险
    char b = static_cast<char>(a);
    double c = static_cast<double>(a);

    std::cout << b << std::endl;
    std::cout << c << std::endl;
#endif

#if 0
    // 使用场景2：指针之间
    int a = 10;
    int *p = &a;

    // 非法的类型转换
    // 不能用于不同指针类型之间的转换
    // char *p1 = static_cast<char *>(p);

    // 但是可以用于void*和其他指针的转换
    void *p2 = static_cast<void *>(p);

    // 可以用于父子类指针的转换，不会进行转换的安全性检查
    Base *b = new Base();
    // 向下转型：基类转子类
    // 向下转型不安全，子类会在继承基类的基础上开辟自己的东西
    // 将基类指针转成子类指针，可能会导致访问非法内存
    // 向上转型是安全的
    Derived *d = static_cast<Derived *>(b);
    // 只是说向下转型不安全，不是说一定是错的，下面介绍的动态转换就可以检查出转换是否安全
    // Derived *d = dynamic_cast<Derived *>(b);
    // 无论将基类的指针转换成子类指针还是反过来，指针本身的值在打印时都是一样的，仍然会指向相同的内存地址
    d->show();
    printf("%p %p\n", b, d);
#endif

// 2、动态转换：dynamic_cast（父子类之间的转换）
#if 0
    // 运行期检查：检查指针是否能够完成转换
    // 如果不能转换，返回nullptr
    Base *b = new Base();
    Derived *d = dynamic_cast<Derived *>(b);
    if (d == nullptr)
    {
        std::cout << "转换失败!\n";
    }
    printf("%p %p\n", b, d);
#endif

// 3、常量转换：const_cast
#if 0
    // 将const转为非const
    const int a = 10;

    // 直接将const int *转为int *，编不过
    // int *p = &a;

    // const_cast可以去除const属性
    int *p = const_cast<int *>(&a);
    *p = 20; // 值可以改（a = 10在符号表里，但是后来取地址的时候给开了个空间，那块空间是*p）

    std::cout << a << " " << *p << std::endl;
#endif

// 4、重定义转换：reinterpret_cast
// C语言强制类型转换有时候编译器会报警告，告诉你这种转换有可能会出问题
// 而reinterpret_cast是C++提供的权限最高的转换，当使用这个时就意味着所有后果自己负责，编译器是不会报警告的
// 用的很少，权限太高了，转换很容易出问题
#if 1
    int a = 10;
    int *p = &a;

    char *c = reinterpret_cast<char *>(p);
    
    // 不能将一个int *指针转成char，差的有点多，一个8个字节，一个1个字节
    // char c = reinterpret_cast<char>(p);

    long c = reinterpret_cast<long>(p);
#endif

    return 0;
}